/* app_fir_fir_example.c */
#include "app.h"
#include "app_fir_data.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/

/* 使用CMSIS-DSP计算FIR, 浮点数
* arm_fir_init_f32()函数中的参数, 除了需要用户提供的内存空间, 还需要执行内部使用缓冲区的大小,
* 两个参数numTaps和blockSize需要小心设定.
*/
void app_arm_fir_f32_example(void)
{
    arm_fir_instance_f32 S;

    PRINTF("%s()\r\n", __func__);

    /* 初始化FIR实例结构体. */
    arm_fir_init_f32(&S, /* points to an instance of the floating-point FIR filter structure. */
        FIR_COEFF_NUM,   /* Number of filter coefficients in the filter. */
        fir_coeff_b_f32_reversed, /* points to the filter coefficients buffer. */
        fir_state_f32,   /* points to the state buffer. */
        FIR_INPUT_NUM ); /* number of samples that are processed per call. */

    /* 开算. */
    TimerCount_Start();
    arm_fir_f32(&S, fir_input_x_f32, fir_output_y_f32, FIR_INPUT_NUM);
    TimerCount_Stop(tick_counter_val);

    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);

}

/* 验证CMSIS-DSP增量FIR计算模式 */
void app_arm_fir_incremental_f32_example(void)
{
    arm_fir_instance_f32 S;
    float32_t fir_input_x_f32_inc[2];

    PRINTF("%s()\r\n", __func__);

    /* 清零输出. */
    memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);

    /* 初始化FIR实例结构体. */
    arm_fir_init_f32(&S, FIR_COEFF_NUM, fir_coeff_b_f32_reversed, fir_state_f32, 4 );

    /* 开算. */
    TimerCount_Start();
    arm_fir_f32(&S, fir_input_x_f32, fir_output_y_f32, 4);
    TimerCount_Stop(tick_counter_val);

    /* 打印中间结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n", tick_counter_val/96u);

    /* 增量计算.
     * fir_input_x_f32_inc和fir_input_x_f32的两块内存没有依赖关系
     * arm_fir_f32()在应用层面上不要求增量计算的输入必须要同之前的输入在物理空间上连续
     */
    fir_input_x_f32_inc[0] = fir_input_x_f32[4];
    fir_input_x_f32_inc[1] = fir_input_x_f32[5];
    TimerCount_Start();
    arm_fir_f32(&S, fir_input_x_f32_inc, fir_output_y_f32+4, 2);
    TimerCount_Stop(tick_counter_val);

    /* 打印最终结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* 使用PowerQuad计算fir. */
void app_pq_fir_f32_example(void)
{
    pq_config_t pq_cfg;

    PRINTF("%s()\r\n", __func__);

    /* setup numbers' format. */
    pq_cfg.inputAFormat = kPQ_Float; /* x[n] format. */
    pq_cfg.inputAPrescale = 0;
    pq_cfg.inputBFormat = kPQ_Float; /* b[m] format.*/
    pq_cfg.inputBPrescale = 0;
    pq_cfg.tmpFormat = kPQ_Float;
    pq_cfg.tmpPrescale = 0;
    pq_cfg.outputFormat = kPQ_Float; /* y[n] format. */
    pq_cfg.outputPrescale = 0;
    pq_cfg.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_cfg.machineFormat = kPQ_Float; /* 除了FFT, 内部都是float. */
    PQ_SetConfig(POWERQUAD, &pq_cfg);

    /* computing ... */
    TimerCount_Start();
    PQ_FIR(POWERQUAD,
           fir_input_x_f32, FIR_INPUT_NUM,
           fir_coeff_b_f32, FIR_COEFF_NUM,
           fir_output_y_f32, PQ_FIR_FIR);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* 验证CMSIS-DSP增量FIR计算模式. */
void app_pq_fir_incremental_f32_example(void)
{
    pq_config_t pq_cfg;

    PRINTF("%s()\r\n", __func__);

    /* 清零输出队列. */
    memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);

    /* setup numbers' format. */
    pq_cfg.inputAFormat = kPQ_Float; /* x[n] format. */
    pq_cfg.inputAPrescale = 0;
    pq_cfg.inputBFormat = kPQ_Float; /* b[m] format.*/
    pq_cfg.inputBPrescale = 0;
    pq_cfg.tmpFormat = kPQ_Float;
    pq_cfg.tmpPrescale = 0;
    pq_cfg.outputFormat = kPQ_Float; /* y[n] format. */
    pq_cfg.outputPrescale = 0;
    pq_cfg.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_cfg.machineFormat = kPQ_Float; /* 除了FFT, 内部都是float. */
    PQ_SetConfig(POWERQUAD, &pq_cfg);

    /* 基本FIR计算模式, 指定了内存地址, 先算4个 ... */
    TimerCount_Start();
    PQ_FIR(POWERQUAD,
           fir_input_x_f32_2, 4, /* 这里换用了fir_input_x_f32_2. */
           fir_coeff_b_f32, FIR_COEFF_NUM,
           fir_output_y_f32, PQ_FIR_FIR);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n", tick_counter_val/96u);

    /* 增量FIR计算模式, 再算2个 ... */
    TimerCount_Start();
    PQ_FIRIncrement(POWERQUAD, 2, FIR_COEFF_NUM, 4); /* xoffset = 4. */
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* 可以独立工作的FIR增量计算模式. */
void PQ_FIRIncrement_standalone(POWERQUAD_Type *base,
       void *pAData, int32_t ALength, int32_t xOffset,
       void *pBData, int32_t BLength,
       void *pResult)
{
    assert(pAData);
    assert(pBData);
    assert(pResult);

    base->INABASE = (uint32_t)pAData;
    base->INBBASE = (uint32_t)pBData;
    base->LENGTH  =  ((uint32_t)BLength << 16U) + (uint32_t)ALength;
    base->OUTBASE = (uint32_t)pResult;
    base->MISC    = xOffset;
    base->CONTROL = (CP_FIR << 4U) | PQ_FIR_INCREMENTAL; /* start computing. */
}


/* 验证fir_inc计算模式:
 * 修改了xoffset之后, 不经过pq_fir的计算, 直接使用pq_fir_inc计算模式, 可以独立工作.
 */
void app_pq_fir_incremental_f32_example_2(void)
{
    pq_config_t pq_cfg;
    int32_t xOffset;

    PRINTF("%s()\r\n", __func__);

    /* 清零输出队列. */
    memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);

    /* setup numbers' format. */
    pq_cfg.inputAFormat = kPQ_Float; /* x[n] format. */
    pq_cfg.inputAPrescale = 0;
    pq_cfg.inputBFormat = kPQ_Float; /* b[m] format.*/
    pq_cfg.inputBPrescale = 0;
    pq_cfg.tmpFormat = kPQ_Float;
    pq_cfg.tmpPrescale = 0;
    pq_cfg.outputFormat = kPQ_Float; /* y[n] format. */
    pq_cfg.outputPrescale = 0;
    pq_cfg.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_cfg.machineFormat = kPQ_Float; /* 除了FFT, 内部都是float. */
    PQ_SetConfig(POWERQUAD, &pq_cfg);

    /* 单独使用增量FIR计算模式. */
    xOffset = 3; /* 从x[3]开始计算, 从y[3]开始输出 */
    TimerCount_Start();
    PQ_FIRIncrement_standalone(POWERQUAD,
       fir_input_x_f32, FIR_INPUT_NUM-xOffset, xOffset,
       fir_coeff_b_f32, FIR_COEFF_NUM,
       fir_output_y_f32);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* 验证fir_inc计算模式:
 * 当使用fir_inc模式时, 已经调用pq_fir()函数后, 修改xoffset之前位置的值, 还是会影响新计算的结果
 * 结论是, PowerQuad计算引擎内部不会缓存之前的计算结果, 每次计算都从原始内存中取数.
 * 这个case同时修改了xoffset的值和原始x[n]数列的历史值, 杂合了example2和example3的实验条件
 * 不建议作为验证证据.
 */
void app_pq_fir_incremental_f32_example_4(void)
{
    pq_config_t pq_cfg;

    PRINTF("%s()\r\n", __func__);

    /* 清零输出队列. */
    memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);

    /* setup numbers' format. */
    pq_cfg.inputAFormat = kPQ_Float; /* x[n] format. */
    pq_cfg.inputAPrescale = 0;
    pq_cfg.inputBFormat = kPQ_Float; /* b[m] format.*/
    pq_cfg.inputBPrescale = 0;
    pq_cfg.tmpFormat = kPQ_Float;
    pq_cfg.tmpPrescale = 0;
    pq_cfg.outputFormat = kPQ_Float; /* y[n] format. */
    pq_cfg.outputPrescale = 0;
    pq_cfg.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_cfg.machineFormat = kPQ_Float; /* 除了FFT, 内部都是float. */
    PQ_SetConfig(POWERQUAD, &pq_cfg);

    fir_input_x_f32_2[0] = fir_input_x_f32[0];
    fir_input_x_f32_2[1] = fir_input_x_f32[1];
    fir_input_x_f32_2[2] = fir_input_x_f32[2];
    fir_input_x_f32_2[3] = fir_input_x_f32[3];

    /* 基本FIR计算模式, 指定了内存地址, 先算4个 ... */
    TimerCount_Start();
    PQ_FIR(POWERQUAD,
           fir_input_x_f32_2, 4, /* 这里换用了fir_input_x_f32_2. */
           fir_coeff_b_f32, FIR_COEFF_NUM,
           fir_output_y_f32, PQ_FIR_FIR);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n", tick_counter_val/96u);

    /* 增量FIR计算模式, 错位一下输入内存, 再算2个 ... */
    fir_input_x_f32_2[0] = fir_input_x_f32[4];
    fir_input_x_f32_2[1] = fir_input_x_f32[5];
    //memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);
    TimerCount_Start();
    PQ_FIRIncrement(POWERQUAD,
        2,             /* ALength. */
        FIR_COEFF_NUM, /* BLength. */
        0);            /* xoffset. */
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* 验证fir_inc计算模式:
 * 设定xoffset=0, 尝试一下非法偏移量的输入.
 * 结果是, pq会自动将x[-1], x[-2]等不存在的位置填0.
 */
void app_pq_fir_incremental_f32_example_3(void)
{
    pq_config_t pq_cfg;
    int32_t xOffset;

    PRINTF("%s()\r\n", __func__);

    /* 清零输出队列. */
    memset(fir_output_y_f32, 0, sizeof(float32_t) * FIR_INPUT_NUM);

    /* setup numbers' format. */
    pq_cfg.inputAFormat = kPQ_Float; /* x[n] format. */
    pq_cfg.inputAPrescale = 0;
    pq_cfg.inputBFormat = kPQ_Float; /* b[m] format.*/
    pq_cfg.inputBPrescale = 0;
    pq_cfg.tmpFormat = kPQ_Float;
    pq_cfg.tmpPrescale = 0;
    pq_cfg.outputFormat = kPQ_Float; /* y[n] format. */
    pq_cfg.outputPrescale = 0;
    pq_cfg.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_cfg.machineFormat = kPQ_Float; /* 除了FFT, 内部都是float. */
    PQ_SetConfig(POWERQUAD, &pq_cfg);

    /* 单独使用增量FIR计算模式. */
    xOffset = 0; /* 尝试一下非法的输入 */
    TimerCount_Start();
    PQ_FIRIncrement_standalone(POWERQUAD,
       fir_input_x_f32, FIR_INPUT_NUM-xOffset, xOffset,
       fir_coeff_b_f32, FIR_COEFF_NUM,
       fir_output_y_f32);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val);

    /* 打印结果. */
    for (uint32_t i = 0; i < FIR_INPUT_NUM; i++)
    {
        PRINTF("[%4d]: %f\r\n", i, fir_output_y_f32[i]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u);
}

/* EOF. */

